﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Application.Expand
{
    public static class ExpressionQuery
    {
        public static IQueryable<TSource> DtoWhere<TSource, TDto>(this IQueryable<TSource> source, TDto? Dto)
        {



            var sProps = typeof(TSource).GetProperties();//反射出表的属性
            var dProps = typeof(TDto).GetProperties();//反射出dto的属性

            //拿到dto表中属性都是string类型，并且属性名称 和表的名称一致的
            var dtoPros = dProps.Where(x => x.PropertyType.FullName == "System.String" && sProps.Any(y => y.Name == x.Name));

            foreach (var dtoProp in dtoPros)
            {
                var value = dtoProp.GetValue(Dto)?.ToString();//遍历出属性的值
                if (!string.IsNullOrEmpty(value))//如果不为空就构建表达式
                {
                    var func = WhereFunc<TSource>(dtoProp.Name, value);//给到属性名称和属性的值
                    source = source.Where(func);
                }
            }
            return source;
        }

        public static Expression<Func<TSource, bool>> WhereFunc<TSource>(string propName, string value)
        {
            ParameterExpression entityPar = Expression.Parameter(typeof(TSource), name: "x");//创建参数节点 节点类型就是表
            var entityParT1 = Expression.Property(entityPar, propName);//此时生成一个表达式为  entityParT1: x.T1
            ConstantExpression dtoValue = Expression.Constant(value);//创建右节点 将dto的属性值放在右边

            //创建一个方法表达式   三个参数 1.表达式 2.linq的方法 方法里面需要传入方法的名称和数据类型 3.右节点参数
            //此时的表达式为containsExp:x.T1.Contains(value)
            MethodCallExpression containsExp = Expression.Call(entityParT1, typeof(string).GetMethod(name: "Contains", new Type[] { typeof(string) }), dtoValue);
            //创建最终的lambda表达式  
            //此时的表达式为whereLambda:x=>x.T1.Contains(value)
            var whereLambda = Expression.Lambda<Func<TSource, bool>>(containsExp, entityPar);
            return whereLambda;
        }
    }
}
